package bomberman;

import gameframework.base.IntegerObservable;
import gameframework.game.CanvasDefaultImpl;
import gameframework.game.Game;
import gameframework.game.GameLevel;
import gameframework.game.GameLevelDefaultImpl;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Container;
import java.awt.Frame;
import java.awt.GridBagLayout;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JPanel;

/**
 * Create a basic game application with menus and displays of lives and score
 */
public class BombermanGameImpl implements Game, Observer {
	protected static final int NB_ROWS = 27;
	protected static final int NB_COLUMNS = 27;
	public static final int MAX_NUMBER_OF_PLAYER = 4;
	public static final int NUMBER_OF_LIVES = 3;
	public static final int NUMBER_OF_BOMB = 1;

	protected CanvasDefaultImpl defaultCanvas = null;
	protected IntegerObservable bomb[] = new IntegerObservable[MAX_NUMBER_OF_PLAYER];
	protected IntegerObservable life[] = new IntegerObservable[MAX_NUMBER_OF_PLAYER];

	private Frame f;
	private GameLevelDefaultImpl currentPlayedLevel = null;

	protected ArrayList<GameLevel> gameLevels;
	protected Iterator<GameLevel> itLevel;

	protected Label playerOnelifeText, playerTwolifeText;
	protected Label lifeValuePlayerOne, lifeValuePlayerTwo;
	protected Label playerOneBombs, playerTwoBombs;

	public BombermanGameImpl() {
		for (int i = 0; i < MAX_NUMBER_OF_PLAYER; ++i)
		{
			life[i] = new IntegerObservable();
			bomb[i] = new IntegerObservable();
		}
		
		playerOnelifeText = new Label("Player one lives:");
		playerTwolifeText = new Label("Player two lives:");
		createGUI();
	}

	public void createGUI() {
		f = new Frame("Default Game");
		f.dispose();

		createMenuBar();
		Container c = createStatusBar();

		defaultCanvas = new CanvasDefaultImpl();
		defaultCanvas.setSize(BombermanGameLevel.SPRITE_SIZE * NB_COLUMNS, BombermanGameLevel.SPRITE_SIZE * NB_ROWS);
		f.add(defaultCanvas);
		f.add(c, BorderLayout.NORTH);
		f.pack();
		f.setVisible(true);

		f.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}

	private void createMenuBar() {
		MenuBar menuBar = new MenuBar();
		Menu file = new Menu("file");
		MenuItem start = new MenuItem("new game");
		MenuItem quit = new MenuItem("quit");
		menuBar.add(file);
		f.setMenuBar(menuBar);

		start.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				start();
			}
		});
		quit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});

		file.add(start);
		file.add(quit);
	}

	private Container createStatusBar() {
		JPanel c = new JPanel();
		GridBagLayout layout = new GridBagLayout();
		c.setLayout(layout);
		lifeValuePlayerOne = new Label(Integer.toString(life[0].getValue()));
		lifeValuePlayerTwo = new Label(Integer.toString(life[1].getValue()));
		playerOneBombs = new Label(Integer.toString(bomb[0].getValue()));
		playerTwoBombs = new Label(Integer.toString(bomb[1].getValue()));
		c.add(playerTwolifeText);
		c.add(lifeValuePlayerTwo);
		c.add(new Label("Bombs:"));
		c.add(playerTwoBombs);
		c.add(playerOnelifeText);
		c.add(lifeValuePlayerOne);
		c.add(new Label("Bombs:"));
		c.add(playerOneBombs);
		return c;
	}

	public Canvas getCanvas() {
		return defaultCanvas;
	}

	public void start() {
		for (int i = 0; i < MAX_NUMBER_OF_PLAYER; ++i) {
			bomb[i].addObserver(this);
			life[i].addObserver(this);
			life[i].setValue(NUMBER_OF_LIVES);
			bomb[i].setValue(NUMBER_OF_BOMB);
		}
		itLevel = gameLevels.iterator();
		try {
			if (currentPlayedLevel != null && currentPlayedLevel.isAlive()) {
				currentPlayedLevel.interrupt();
				currentPlayedLevel = null;
			}
			currentPlayedLevel = (GameLevelDefaultImpl) itLevel.next();
			currentPlayedLevel.start();
			currentPlayedLevel.join();
		} catch (Exception e) {
		}

	}

	public void restore() {
		System.out.println("restore(): Unimplemented operation");
	}

	public void save() {
		System.out.println("save(): Unimplemented operation");
	}

	public void pause() {
		System.out.println("pause(): Unimplemented operation");
		// currentPlayedLevel.suspend();
	}

	public void resume() {
		System.out.println("resume(): Unimplemented operation");
		// currentPlayedLevel.resume();
	}

	public IntegerObservable[] bomb() {
		return bomb;
	}

	public IntegerObservable[] life() {
		return life;
	}

	public void setLevels(ArrayList<GameLevel> levels) {
		gameLevels = levels;
	}

	/*
	 * update method so as to make Game as an updatable Observer (TODO Handle 2
	 * or more players)
	 */
	public void update(Observable o, Object arg) {
		if (o instanceof IntegerObservable) {
			IntegerObservable observable = (IntegerObservable) o;
			handleScoreObservable(observable);
			handleLifeObservable(observable);
		}
	}

	private void handleLifeObservable(IntegerObservable observable) {
		int i = 0;
		for (IntegerObservable lifeObservable : life) {
			if (observable == lifeObservable) {
				int lives = observable.getValue();
				if (i == 0)
				{
					lifeValuePlayerOne.setText(Integer.toString(lives));
					if (lives == 0) {
						//fin du jeu
						currentPlayedLevel.interrupt();
						currentPlayedLevel.end();
					}
				}
				else if(i == 1)
				{
					lifeValuePlayerTwo.setText(Integer.toString(lives));
					if (lives == 0) {
						//fin du jeu
						currentPlayedLevel.interrupt();
						currentPlayedLevel.end();
					}
				}
			}
			++i;
		}
	}

	private void handleScoreObservable(IntegerObservable observable) {
		int i = 0;
		for (IntegerObservable bombObservable : bomb) {
			if( i == 0)
			{
				if (observable == bombObservable) {
					playerOneBombs.setText(Integer.toString(observable.getValue()));
				}
			}
			else if(i == 1)
			{
				if (observable == bombObservable) {
					playerTwoBombs.setText(Integer.toString(observable.getValue()));
				}
			}
			++i;
		}
	}

}
